package com.qiwenshare.file.util;


public final class CheckPwdUtils {
    private CheckPwdUtils(){}
    /**
     * @param password            密码字符串
     * @return  符合长度要求 返回true
     */
    public static boolean checkPasswordLength(String password) {

        return password.length() >= Integer.parseInt(PwdSecurityConfig.MIN_LENGTH) &&
                password.length() <= Integer.parseInt(PwdSecurityConfig.MAX_LENGTH);
    }

    /**
     * @param password            密码字符串
     * @return  包含数字 返回true
     */
    public static boolean checkContainDigit(String password) {
        char[] chPass = password.toCharArray();
        boolean flag = false;
        int num_count = 0;

        for (char pass : chPass) {
            if (Character.isDigit(pass)) {
                num_count++;
            }
        }

        if (num_count >= 1){
            flag = true;
        }
        return flag;
    }

    /**
     * @param password            密码字符串
     * @return  包含字母 返回true
     */
    public static boolean checkContainCase(String password) {
        char[] chPass = password.toCharArray();
        boolean flag = false;
        int char_count = 0;

        for (char pass : chPass) {
            if (Character.isLetter(pass)) {
                char_count++;
            }
        }

        if (char_count >= 1) {
            flag = true;
        }
        return flag;
    }

    /**
     * @param password            密码字符串
     * @return  包含小写字母 返回true
     */
    public static boolean checkContainLowerCase(String password) {
        char[] chPass = password.toCharArray();
        boolean flag = false;
        int char_count = 0;

        for (char pass : chPass) {
            if (Character.isLowerCase(pass)) {
                char_count++;
            }
        }

        if (char_count >= 1) {
            flag = true;
        }
        return flag;
    }

    /**
     * @param password            密码字符串
     * @return  包含大写字母 返回true
     */
    public static boolean checkContainUpperCase(String password) {
        char[] chPass = password.toCharArray();
        boolean flag = false;
        int char_count = 0;

        for (char pass : chPass) {
            if (Character.isUpperCase(pass)) {
                char_count++;
            }
        }

        if (char_count >= 1) {
            flag = true;
        }
        return flag;
    }

    /**
     * @param password            密码字符串
     * @return  包含特殊符号 返回true
     */
    public static boolean checkContainSpecialChar(String password) {
        char[] chPass = password.toCharArray();
        boolean flag = false;
        int special_count = 0;

        for (char pass : chPass) {
            if (PwdSecurityConfig.SPECIAL_CHAR.indexOf(pass) != -1) {
                special_count++;
            }
        }

        if (special_count >= 1){
            flag = true;
        }
        return flag;
    }

    /**
     * @param password            密码字符串
     * @return  含有横向连续字符串 返回true
     */
    public static boolean checkLateralKeyboardSite(String password) {
        String t_password = password;
        //将所有输入字符转为小写
        t_password = t_password.toLowerCase();
        int n = t_password.length();
        //键盘横向规则检测
        boolean flag = false;
        int arrLen = PwdSecurityConfig.KEYBOARD_HORIZONTAL_ARR.length;
        int limit_num = Integer.parseInt(PwdSecurityConfig.LIMIT_HORIZONTAL_NUM_KEY) ;

        for(int i=0; i+limit_num<=n; i++) {
            String str = t_password.substring(i, i+limit_num);
            String distinguishStr = password.substring(i, i+limit_num);

            for(int j=0; j<arrLen; j++) {
                String PwdSecurityConfigStr = PwdSecurityConfig.KEYBOARD_HORIZONTAL_ARR[j];
                String revOrderStr = new StringBuffer(PwdSecurityConfig.KEYBOARD_HORIZONTAL_ARR[j]).reverse().toString();

                //检测包含字母(区分大小写)
                if (PwdSecurityConfig.CHECK_DISTINGGUISH_CASE) {
                    //考虑 大写键盘匹配的情况
                    String UpperStr = PwdSecurityConfig.KEYBOARD_HORIZONTAL_ARR[j].toUpperCase();
                    if((PwdSecurityConfigStr.contains(distinguishStr)) || (UpperStr.contains(distinguishStr))) {
                        return true;
                    }
                    //考虑逆序输入情况下 连续输入
                    String revUpperStr = new StringBuffer(UpperStr).reverse().toString();
                    if((revOrderStr.contains(distinguishStr)) || (revUpperStr.contains(distinguishStr))) {
                        return true;
                    }
                }else {
                    if(PwdSecurityConfigStr.contains(str)) {
                        return true;
                    }
                    //考虑逆序输入情况下 连续输入
                    if(revOrderStr.contains(str)) {
                        return true;
                    }
                }
            }
        }
        return flag;
    }

    /**
     * @param password            密码字符串
     * @return  含有斜向连续字符串 返回true
     */
    public static boolean checkKeyboardSlantSite(String password) {
        String t_password = password;
        t_password = t_password.toLowerCase();
        int n = t_password.length();
        //键盘斜线方向规则检测
        boolean flag = false;
        int arrLen = PwdSecurityConfig.KEYBOARD_SLOPE_ARR.length;
        int limit_num = Integer.parseInt(PwdSecurityConfig.LIMIT_SLOPE_NUM_KEY);

        for(int i=0; i+limit_num<=n; i++) {
            String str = t_password.substring(i, i+limit_num);
            String distinguishStr = password.substring(i, i+limit_num);
            for(int j=0; j<arrLen; j++) {
                String PwdSecurityConfigStr = PwdSecurityConfig.KEYBOARD_SLOPE_ARR[j];
                String revOrderStr = new StringBuffer(PwdSecurityConfig.KEYBOARD_SLOPE_ARR[j]).reverse().toString();
                //检测包含字母(区分大小写)
                if (PwdSecurityConfig.CHECK_DISTINGGUISH_CASE) {

                    //考虑 大写键盘匹配的情况
                    String UpperStr = PwdSecurityConfig.KEYBOARD_SLOPE_ARR[j].toUpperCase();
                    if((PwdSecurityConfigStr.contains(distinguishStr)) || (UpperStr.contains(distinguishStr))) {
                        return true;
                    }
                    //考虑逆序输入情况下 连续输入
                    String revUpperStr = new StringBuffer(UpperStr).reverse().toString();
                    if((revOrderStr.contains(distinguishStr)) || (revUpperStr.contains(distinguishStr))) {
                        return true;
                    }
                }else {
                    if(PwdSecurityConfigStr.contains(str)) {
                        return true;
                    }
                    //考虑逆序输入情况下 连续输入
                    if(revOrderStr.contains(str)) {
                        return true;
                    }
                }
            }
        }
        return flag;
    }

    /**
     * @param password            密码字符串
     * @return  含有a-z,z-a连续字符串 返回true
     */
    public static boolean checkSequentialChars(String password) {
        String t_password = password;
        boolean flag = false;
        int limit_num = Integer.parseInt(PwdSecurityConfig.LIMIT_LOGIC_NUM_CHAR);
        int normal_count;
        int reversed_count;

        //检测包含字母(区分大小写)
        if (!PwdSecurityConfig.CHECK_DISTINGGUISH_CASE) {
            t_password = t_password.toLowerCase();
        }
        int n = t_password.length();
        char[] pwdCharArr = t_password.toCharArray();

        for (int i=0; i+limit_num<=n; i++) {
            normal_count = 0;
            reversed_count = 0;
            for (int j=0; j<limit_num-1; j++) {
                if (pwdCharArr[i+j+1]-pwdCharArr[i+j]==1) {
                    normal_count++;
                    if(normal_count == limit_num -1){
                        return true;
                    }
                }

                if (pwdCharArr[i+j]-pwdCharArr[i+j+1]==1) {
                    reversed_count++;
                    if(reversed_count == limit_num -1){
                        return true;
                    }
                }
            }
        }
        return flag;
    }

    /**
     * @param password            密码字符串
     * @return  含有aaaa,1111等连续字符串 返回true
     */
    public static boolean checkSequentialSameChars(String password) {
        int n = password.length();
        char[] pwdCharArr = password.toCharArray();
        boolean flag = false;
        int limit_num = Integer.parseInt(PwdSecurityConfig.LIMIT_NUM_SAME_CHAR);
        int count;
        for (int i=0; i+limit_num<=n; i++) {
            count=0;
            for (int j=0; j<limit_num-1; j++) {
                if(pwdCharArr[i+j] == pwdCharArr[i+j+1]) {
                    count++;
                    if (count == limit_num -1){
                        return true;
                    }
                }
            }
        }
        return flag;
    }

    /**
     * @param password  密码字符串
     * @return  符合要求 返回true
     */
    public static boolean EvalPWD(String password) {
        if (password == null || "".equals(password)) {
            return false;
        }
        boolean flag;

        if (PwdSecurityConfig.CHECK_PASSWORD_LENGTH){
            flag = checkPasswordLength(password);
            if (!flag) {
                return false;
            }
        }
        //大小写，数字，特殊符号，满足其中三种即可
        int i = 0;

        if (PwdSecurityConfig.CHECK_CONTAIN_DIGIT){
            flag = checkContainDigit(password);
            if (flag) {
                i++;
            }
        }

        if (PwdSecurityConfig.CHECK_DISTINGGUISH_CASE){
            //检测包含小写字母
            if (PwdSecurityConfig.CHECK_LOWER_CASE){
                flag = checkContainLowerCase(password);
                if (flag) {
                    i++;
                }
            }

            //检测包含大写字母
            if (PwdSecurityConfig.CHECK_UPPER_CASE){
                flag = checkContainUpperCase(password);
                if (flag) {
                    i++;
                }
            }
        }else {
            flag = checkContainCase(password);
            if (!flag) {
                return false;
            }
        }

        if (PwdSecurityConfig.CHECK_CONTAIN_SPECIAL_CHAR){
            flag = checkContainSpecialChar(password);
            if (flag) {
                i++;
            }
        }
        if(i<3){
            return false;
        }

        if (PwdSecurityConfig.CHECK_HORIZONTAL_KEY_SEQUENTIAL){
            flag = checkLateralKeyboardSite(password);
            if (flag) {
                return false;
            }
        }

        if (PwdSecurityConfig.CHECK_SLOPE_KEY_SEQUENTIAL){
            flag = checkKeyboardSlantSite(password);
            if (flag) {
                return false;
            }
        }


        if (PwdSecurityConfig.CHECK_LOGIC_SEQUENTIAL){
            flag = checkSequentialChars(password);
            if (flag) {
                return false;
            }
        }

        if (PwdSecurityConfig.CHECK_SEQUENTIAL_CHAR_SAME){
            flag = checkSequentialSameChars(password);
            return !flag;
        }
        return flag;
    }

    /**
     *
     #当设置checkContainUpperLowerCase为enable时，区分大小写
     #当系统级别为2时：checkContainDigit默认为enable，checkContainUpperLowerCase默认为disable
     #当系统级别为2时，checkContainLowerCase默认为disable，checkContainUpperCase默认为disable
     #当系统级别为2时，checkContainSpecialChar默认为disable
     #当系统级别为3时：checkContainDigit默认为enable，checkContainUpperLowerCase默认为disable
     #当系统级别为3时，checkContainLowerCase默认为disable，checkContainUpperCase默认为disable
     #当系统级别为3时，checkContainSpecialChar默认为enable
     #是否检测包含数字
     checkContainDigit=enable
     #是否检测包含大小写字母，区分密码口令大小写
     checkContainUpperLowerCase = enable
     #是否检测包含小写字母
     checkContainLowerCase = enable
     #是否检测包含大写字母
     checkContainUpperCase = enable
     #是否检测包含特殊符号
     checkContainSpecialChar=enable
     #支持自定义特殊符号集合
     specialCharSet="!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~"

     #检测键盘按键连续 比如qwer、1qaz、0okm等
     #允许横向最大连续num为7，最小为3
     #允许斜向最大连续num为4，最小为3
     #当系统级别为2时：checkHorizontalKeySequential默认为enable，horizontalKeyLimitNum默认为4
     #当系统级别为2时，checkSlopeKeySequential默认为enable，slopeKeyLimitNum默认为4
     #当系统级别为3时：checkHorizontalKeySequential默认为enable，horizontalKeyLimitNum默认为3
     #当系统级别为3时，checkSlopeKeySequential默认为enable，slopeKeyLimitNum默认为3
     #是否检测键盘横向连续
     checkHorizontalKeySequential=enable
     #允许键盘横向连续最小数值，如为空，则设置为默认值
     horizontalKeyLimitNum=3
     #是否检测键盘斜向连续
     checkSlopeKeySequential=enable
     #允许键盘斜向连续最小数值，如为空，则设置为默认值
     slopeKeyLimitNum=3

     #检测逻辑位置连续 比如1234、abcd等
     #当系统级别为2时，checkLogicSequential默认为enable，logicLimitNum默认为4
     #当系统级别为3时，checkLogicSequential默认为enable，logicLimitNum默认为3
     #是否检测逻辑位置连续
     checkLogicSequential=enable
     #允许逻辑位置连续最小数值，如为空，则设置为默认值
     logicLimitNum=3

     #检测相邻字符相同 比如aaaa、2222、@@@@等
     #当系统级别为2时，checkSequentialCharSame默认为enable，sequentialCharNum默认为4
     #当系统级别为3时，checkSequentialCharSame默认为enable，sequentialCharNum默认为3
     #是否检测相邻字符相同
     checkSequentialCharSame=enable
     #允许相邻位置相同最小连续数，如为空，则设置为默认值
     sequentialCharNum=3
     */
    private static class PwdSecurityConfig {

        /**
         * 是否检测密码口令长度标识
         *      #检测密码口令长度
         *      #当checkPasswordLength为disable时，下面两项设置无效
         *      #其他检测功能设置为disable时，对应设置项设置数据无效
         *      #当系统级别为2或3时，checkPasswordLength默认为enable
         *      #当系统级别为2或3时，limitPassMinLength默认为8，limitPassMaxLength默认为20
         *      #是否检测密码口令长度，如为enable则检测，如为disable则不检测，如为空，
         */
        public static  final boolean CHECK_PASSWORD_LENGTH = true;
        /**
         * 密码最小长度，默认为8
         */
        public static final String MIN_LENGTH = "8";
        /**
         * 密码最大长度，默认为20
         */
        public static final String MAX_LENGTH = "20";

        /**
         * 是否包含数字
         */
        public static final boolean CHECK_CONTAIN_DIGIT = true;
        /**
         * 是否区分大小写
         */
        public static final boolean CHECK_DISTINGGUISH_CASE = true;
        /**
         * 是否包含小写字母
         */
        public static final boolean CHECK_LOWER_CASE = true;
        /**
         * 是否包含大写字母
         */
        public static final boolean CHECK_UPPER_CASE = true;
        /**
         * 是否包含特殊符号
         */
        public static final boolean CHECK_CONTAIN_SPECIAL_CHAR = true;
        /**
         * 默认的特殊符号集合
         */
        public static final String DEFAULT_SPECIAL_CHAR="!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~";
        /**
         * 配置中的特殊符号集合
         */
        public static final String SPECIAL_CHAR  = DEFAULT_SPECIAL_CHAR;

        /**
         * 是否检测键盘按键横向连续
         */
        public static final boolean CHECK_HORIZONTAL_KEY_SEQUENTIAL  = true;
        /**
         * 键盘物理位置横向不允许最小的连续个数
         */
        public static final String LIMIT_HORIZONTAL_NUM_KEY = "5";
        /**
         * 是否检测键盘按键斜向连续
         */
        public static final boolean CHECK_SLOPE_KEY_SEQUENTIAL = true;
        /**
         * 键盘物理位置斜向不允许最小的连续个数
         */
        public static final String LIMIT_SLOPE_NUM_KEY = "5";

        /**
         * 是否检测逻辑位置连续
         */
        public static final boolean CHECK_LOGIC_SEQUENTIAL = true;
        /**
         * 密码口令中字符在逻辑位置上不允许最小的连续个数
         */
        public static final String LIMIT_LOGIC_NUM_CHAR = "4";

        /**
         * 是否检测连续字符相同
         */
        public static final boolean CHECK_SEQUENTIAL_CHAR_SAME = true;
        /**
         * 密码口令中相同字符不允许最小的连续个数
         */
        public static final String LIMIT_NUM_SAME_CHAR = "4";

        /**
         * 键盘横向方向规则
         */
        private static final String[] KEYBOARD_HORIZONTAL_ARR = {
                "01234567890",
                "qwertyuiop",
                "asdfghjkl",
                "zxcvbnm",
        };
        /**
         * 键盘斜线方向规则
         */
        private static final String[] KEYBOARD_SLOPE_ARR = {
                "1qaz",
                "2wsx",
                "3edc",
                "4rfv",
                "5tgb",
                "6yhn",
                "7ujm",
                "8ik,",
                "9ol.",
                "0p;/",
                "=[;.",
                "-pl,",
                "0okm",
                "9ijn",
                "8uhb",
                "7ygv",
                "6tfc",
                "5rdx",
                "4esz"
        };

    }
}
